/**
 * @file looper.hpp
 * @brief 异步缓冲区的事件循环的设计
 * @author zhaobohan (zhaobohan_free@163.com)
 */

#ifndef __M_LOOP_H__
#define __M_LOOP_H__
#include "util.hpp"
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <functional>
#include "buffer.hpp"

namespace mylogs {

// 异步的Loop循环
class AsyncLooper 
{
public:
    using Functor = std::function<void(Buffer &buffer)>;
    using ptr = std::shared_ptr<AsyncLooper>;
    AsyncLooper(const Functor &cb)
        : _running(true), _looper_callback(cb), _thread(std::thread(&AsyncLooper::worker_loop, this)) 
    {}

    ~AsyncLooper() 
    { 
        stop(); 
    }

    void stop()
    { 
        _running = false; 
        _pop_cond.notify_all();
        _thread.join();
    }

    // 异步模式下推送一个日志
    void push(const std::string &msg)
    {
        if (_running == false) return;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _push_cond.wait(lock, [&]{ return _tasks_push.writeAbleSize() >= msg.size(); });
            _tasks_push.push(msg.c_str(), msg.size());
        }
        _pop_cond.notify_all();
    }
private:
    void worker_loop()
    {
        while(1)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if (_running == false && _tasks_push.empty()) { return; }
                _pop_cond.wait(lock, [&]{ return !_tasks_push.empty() || !_running; });
                _tasks_push.swap(_tasks_pop);
            }
            _push_cond.notify_all();
            _looper_callback(_tasks_pop);
            _tasks_pop.reset();
        }
        return;
    }

private:
    Functor _looper_callback;
private:
    std::mutex _mutex;
    std::atomic<bool> _running;
    std::condition_variable _push_cond;
    std::condition_variable _pop_cond;

    // 设计的两个线程池
    Buffer _tasks_push;
    Buffer _tasks_pop;
    std::thread _thread;
};
}
#endif